home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Demos / DMBoids / music.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  28.4 KB  |  1,116 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Music.cpp
  3. //
  4. // Desc: 
  5. //       
  6. // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <tchar.h>
  11. #include <oleauto.h>
  12. #include <stdio.h>
  13. #include "DXUtil.h"
  14. #include "music.h"
  15.  
  16.  
  17.  
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Name: 
  22. // Desc: 
  23. //-----------------------------------------------------------------------------
  24. BoidMusic::BoidMusic()
  25. {
  26.     m_dwBeatsSinceLastMotif = 0;
  27.     m_pSegment = NULL;
  28.     m_pPort = NULL;
  29.     m_pDMusic = NULL;
  30.     m_fCollapsed = FALSE;
  31.     m_dwIndex = 0;
  32.     m_pBand = NULL;
  33.     m_pStyle = NULL;
  34.     m_pChordMap = NULL;
  35.     long x;
  36.     for (x = 0; x < 6; x++)
  37.     {
  38.         m_pTemplateSegments[x] = NULL;
  39.         m_pPrimarySegments[x] = NULL;
  40.         m_pMotifSegments[x] = NULL;
  41.     }
  42.     m_pPrimarySegments[1] = NULL;
  43.     m_pTransitionSegment = NULL;
  44.     m_pComposer = NULL;
  45.     m_pLoader = NULL;
  46.     m_pPerformance = NULL;
  47. }
  48.  
  49.  
  50.  
  51.  
  52. //-----------------------------------------------------------------------------
  53. // Name: 
  54. // Desc: 
  55. //-----------------------------------------------------------------------------
  56. BoidMusic::~BoidMusic()
  57. {
  58.     long x;
  59.     if (m_pSegment)
  60.     {
  61.         m_pSegment->Release();
  62.     }
  63.     if (m_pBand)
  64.     {
  65.         if(m_pPerformance)
  66.         {
  67.             m_pBand->Unload(m_pPerformance);
  68.         }
  69.         m_pBand->Release();
  70.     }
  71.     if (m_pGraph)
  72.     {
  73.         m_pGraph->Release();
  74.     }
  75.     if (m_pPort)
  76.     {
  77.         m_pPort->Release();
  78.     }
  79.     if (m_pDMusic)
  80.     {
  81.         m_pDMusic->Release();
  82.     }
  83.     for (x = 0; x< 6; x++)
  84.     {
  85.         if (m_pTemplateSegments[x])
  86.         {
  87.             m_pTemplateSegments[x]->Release();
  88.         }
  89.         if (m_pPrimarySegments[x])
  90.         {
  91.             m_pPrimarySegments[x]->Release();
  92.         }
  93.         if (m_pMotifSegments[x])
  94.         {
  95.             m_pMotifSegments[x]->Release();
  96.         }
  97.     }
  98.     if (m_pStyle)
  99.     {
  100.         m_pStyle->Release();
  101.     }
  102.     if (m_pChordMap)
  103.     {
  104.         m_pChordMap->Release();
  105.     }
  106.     if (m_pTransitionSegment)
  107.     {
  108.         m_pTransitionSegment->Release();
  109.     }
  110.     if (m_pComposer)
  111.     {
  112.         m_pComposer->Release();
  113.     }
  114.     if (m_pLoader)
  115.     {
  116.         m_pLoader->Release();
  117.     }
  118.     if (m_pPerformance)
  119.     {
  120.         m_pPerformance->Release();
  121.     }
  122.     if( m_hNotify )
  123.     {
  124.         CloseHandle( m_hNotify );
  125.     }
  126. }
  127.  
  128.  
  129.  
  130.  
  131. //-----------------------------------------------------------------------------
  132. // Name: 
  133. // Desc: 
  134. //-----------------------------------------------------------------------------
  135. BOOL BoidMusic::LoadStyle()
  136. {
  137.     if (m_pStyle) m_pStyle->Release();
  138.  
  139.     DMUS_OBJECTDESC ObjectDescript;
  140.     ObjectDescript.guidClass = CLSID_DirectMusicStyle;
  141.     wcscpy(ObjectDescript.wszFileName, L"Boids2.sty");
  142.     ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
  143.     ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
  144.     if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicStyle, (void**)&m_pStyle)))
  145.     {
  146.         BSTR bstr = SysAllocString(L"Default");
  147.         m_pStyle->GetBand(bstr, &m_pBand) ;
  148.         SysFreeString(bstr);
  149.  
  150.         return TRUE;
  151.     }
  152.  
  153.     return FALSE;
  154. }
  155.  
  156.  
  157.  
  158.  
  159. //-----------------------------------------------------------------------------
  160. // Name: 
  161. // Desc: This loads a precomposed segment.
  162. //-----------------------------------------------------------------------------
  163. BOOL BoidMusic::LoadSegment()
  164. {
  165.     if (m_pSegment) m_pSegment->Release();
  166.  
  167.     DMUS_OBJECTDESC ObjectDescript;
  168.     ObjectDescript.guidClass = CLSID_DirectMusicSegment;
  169.     wcscpy(ObjectDescript.wszFileName, L"BoidsD.sgt");
  170.     ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
  171.     ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
  172.     if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicSegment, (void**)&m_pSegment)))
  173.     {
  174.  
  175.         return TRUE;
  176.     }
  177.  
  178.     return FALSE;
  179. }
  180.  
  181.  
  182.  
  183.  
  184. //-----------------------------------------------------------------------------
  185. // Name: 
  186. // Desc: Load the dls set that the band needs, but just leave it in the cache.
  187. //          Then, it will be referenced and loaded by the bands in the styles and 
  188. //       segments.
  189. //-----------------------------------------------------------------------------
  190. HRESULT BoidMusic::LoadDLS()
  191. {
  192.     DMUS_OBJECTDESC dmod;
  193.     dmod.dwSize      = sizeof(DMUS_OBJECTDESC);
  194.     dmod.guidClass   = CLSID_DirectMusicCollection;
  195.     dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ;
  196.     wcscpy(dmod.wszFileName, L"Boids.dls");
  197.  
  198.     IDirectMusicCollection* pCollect = NULL;
  199.     if( FAILED( m_pLoader->GetObject( &dmod, IID_IDirectMusicCollection, 
  200.                                       (VOID**)&pCollect ) ) )
  201.         return E_FAIL;
  202.  
  203.     pCollect->Release();
  204.     return S_OK;
  205. }
  206.  
  207.  
  208.  
  209.  
  210. //-----------------------------------------------------------------------------
  211. // Name: 
  212. // Desc: Load the Boids chord map.
  213. //-----------------------------------------------------------------------------
  214. BOOL BoidMusic::LoadChordMap()
  215. {
  216.     if (m_pChordMap) m_pChordMap->Release();
  217.  
  218.     DMUS_OBJECTDESC ObjectDescript;
  219.     ObjectDescript.guidClass = CLSID_DirectMusicChordMap;
  220.     wcscpy(ObjectDescript.wszFileName, L"Boids.cdm");
  221.     ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
  222.     ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
  223.     if (SUCCEEDED(m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicChordMap, (void**)&m_pChordMap)))
  224.     {
  225.         return TRUE;
  226.     }
  227.  
  228.     return FALSE;
  229. }
  230.  
  231.  
  232.  
  233.  
  234. //-----------------------------------------------------------------------------
  235. // Name: 
  236. // Desc: Load a template and place it in the m_pTemplateSegments[] array.
  237. //-----------------------------------------------------------------------------
  238. BOOL BoidMusic::LoadTemplate(DWORD dwIndex, WCHAR * pwzName)
  239. {     
  240.     if (m_pTemplateSegments[dwIndex]) m_pTemplateSegments[dwIndex]->Release();
  241.  
  242.     HRESULT hr;
  243.     DMUS_OBJECTDESC ObjectDescript;
  244.  
  245.     ObjectDescript.guidClass = CLSID_DirectMusicSegment;
  246.     wcscpy(ObjectDescript.wszFileName, pwzName);
  247.     ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
  248.     ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
  249.     if (SUCCEEDED( hr = m_pLoader->GetObject(&ObjectDescript, IID_IDirectMusicSegment, (void**)&m_pTemplateSegments[dwIndex])))
  250.     {
  251.         return TRUE;
  252.     }
  253.  
  254.     return FALSE;
  255. }
  256.  
  257.  
  258.  
  259.  
  260. //-----------------------------------------------------------------------------
  261. // Name: 
  262. // Desc: Use the composer to compose a style segment from a previously loaded
  263. //         template segment, the boids chord map and style. Place the
  264. //         segment in the m_pPrimarySegments[] array.
  265. //-----------------------------------------------------------------------------
  266. void BoidMusic::ComposeSegment(DWORD dwIndex)
  267. {     
  268.  
  269.     if (m_pComposer && m_pStyle && m_pChordMap && m_pTemplateSegments[dwIndex])
  270.     {
  271.         if (m_pPrimarySegments[dwIndex])
  272.         {
  273.             m_pPrimarySegments[dwIndex]->Release();
  274.             m_pPrimarySegments[dwIndex] = NULL;
  275.         }
  276.         m_pComposer->ComposeSegmentFromTemplate(
  277.             m_pStyle,
  278.             m_pTemplateSegments[dwIndex],
  279.             1,
  280.             m_pChordMap,
  281.             &m_pPrimarySegments[dwIndex]);
  282.         if (m_pPrimarySegments[dwIndex])
  283.         {
  284.             m_pPrimarySegments[dwIndex]->SetRepeats(100);
  285.  
  286.         }
  287.     }
  288. }
  289.  
  290.  
  291.  
  292.  
  293. //-----------------------------------------------------------------------------
  294. // Name: 
  295. // Desc: Pull the named motif segment from the boids style.
  296. //         Note that we currently use the OLE BSTR string approach.
  297. //         This will probably change in the next beta.
  298. //-----------------------------------------------------------------------------
  299. BOOL BoidMusic::GetMotif(DWORD dwIndex, WCHAR * pszName)
  300.     if (m_pStyle)
  301.     {    
  302.         if (SUCCEEDED(m_pStyle->GetMotif(pszName, &m_pMotifSegments[dwIndex])))
  303.         {
  304.             return TRUE;
  305.         }
  306.     }
  307.  
  308.     return FALSE;
  309. }
  310.  
  311.  
  312.  
  313.  
  314. //-----------------------------------------------------------------------------
  315. // Name: 
  316. // Desc: Check for a notify event. Since we are only waiting for
  317. //         notification of beats, we increment out beat counter. The beat counter
  318. //       is used by the boids app to manage the number of motifs allowed at any
  319. //       point in time. This keeps things from getting too overcrowded.
  320. //       Alternatively, the notifications could be used to synchronize graphic
  321. //       events.
  322. //-----------------------------------------------------------------------------
  323. void BoidMusic::HandleNotifies()
  324. {
  325.     DMUS_NOTIFICATION_PMSG* pMsg;
  326.     if( m_hNotify && m_pPerformance)
  327.     {
  328.         WaitForSingleObject(m_hNotify, 2);
  329.         while( S_OK == m_pPerformance->GetNotificationPMsg(&pMsg))
  330.         {
  331.             m_pPerformance->FreePMsg((DMUS_PMSG*)pMsg);
  332.             m_dwBeatsSinceLastMotif++;
  333.         }
  334.     }
  335. }
  336.  
  337.  
  338.  
  339.  
  340. //-----------------------------------------------------------------------------
  341. // Name: 
  342. // Desc: This is called by the app, once it gets its main window up.
  343. //       Activate the synth and start the music playing.
  344. //-----------------------------------------------------------------------------
  345. void BoidMusic::StartMusic()
  346. {
  347.     if (m_pDMusic)
  348.     {
  349.         m_pDMusic->Activate(TRUE);
  350.     }
  351.     if (m_pPrimarySegments[0])
  352.     {
  353.         m_pPerformance->PlaySegment( 
  354.             m_pPrimarySegments[0], 0, 0, NULL);
  355.         m_dwIndex = 0;
  356.     }    
  357. }
  358.  
  359.  
  360.  
  361.  
  362. //-----------------------------------------------------------------------------
  363. // Name: 
  364. // Desc: This is called from the graphics loop. As we get closer to the center
  365. //       of the flock of birds, increase the number of echoes for the echo tool,
  366. //       and also increase the duration scalings (makes the note durations
  367. //       longer.)
  368. //-----------------------------------------------------------------------------
  369. void BoidMusic::SetDistance(double fDistance)
  370. {
  371.     double fTemp = fDistance - 10.0;
  372.     fTemp = 70.0 - fTemp;
  373.     if (fTemp < 0.0) fTemp = 0.0;
  374.     m_Tool.m_dwEcho = (DWORD)(fTemp / 15.0);
  375.     m_Tool.m_dwStartRatio = (DWORD)(75 + fTemp);
  376.     m_Tool.m_dwRatio = m_Tool.m_dwStartRatio;
  377. }
  378.  
  379.  
  380.  
  381.  
  382. //-----------------------------------------------------------------------------
  383. // Name: 
  384. // Desc: Whenever the flock is about to hit a sphere, this is called. It
  385. //       chooses the next segment to go to and plays the planet motif leading
  386. //       into the next segment. Notice how it takes the start time of the 
  387. //       planet motif, adds one, and uses that to start the segment, but on a
  388. //       beat boundary. This tricks the segment to start one beat later than
  389. //       the motif, creating a smooth musical transition.
  390. //-----------------------------------------------------------------------------
  391. void BoidMusic::Transition()
  392. {
  393.     if (!m_fCollapsed && (m_dwBeatsSinceLastMotif > 2))
  394.     {
  395.         static DWORD dwChoice[8] = { 0, 2, 1, 3, 0, 4, 1, 5 };
  396.         m_dwIndex++;
  397.         if (m_dwIndex > 8) m_dwIndex = 2;
  398.         if (m_dwIndex > 0) 
  399.         {
  400.             if (m_pMotifSegments[0] && m_pPrimarySegments[dwChoice[m_dwIndex-1]]) 
  401.             {
  402.                 IDirectMusicSegmentState *pState = NULL;
  403.                 m_pPerformance->PlaySegment(
  404.                     m_pMotifSegments[0], (DMUS_SEGF_SECONDARY | DMUS_SEGF_BEAT ), 0, &pState);
  405.                 if (pState)
  406.                 {
  407.                     MUSIC_TIME mtTime;
  408.                     pState->GetStartTime(&mtTime);
  409.                     pState->Release();
  410.                     mtTime++;
  411.                     m_pPerformance->PlaySegment( 
  412.                             m_pPrimarySegments[dwChoice[m_dwIndex-1]], DMUS_SEGF_BEAT , mtTime, NULL);
  413.                 }
  414.             }
  415.         }
  416.     }
  417. }
  418.  
  419.  
  420.  
  421.  
  422. //-----------------------------------------------------------------------------
  423. // Name: 
  424. // Desc: When the migration force is turned off, the birds start to migrate
  425. //       away. So, this starts the migration theme. Note that it plays once,
  426. //       and then one of the regular segments is queued to pick up after it.
  427. //-----------------------------------------------------------------------------
  428. void BoidMusic::Migrate()
  429. {
  430.     if (m_pSegment) 
  431.     {
  432.         m_pPerformance->PlaySegment( 
  433.                     m_pSegment, DMUS_SEGF_BEAT , 0, NULL);
  434.     }
  435.     if (m_pPrimarySegments[2])
  436.     {
  437.         m_pPerformance->PlaySegment( 
  438.                     m_pPrimarySegments[2], DMUS_SEGF_QUEUE , 0, NULL);
  439.     }
  440. }
  441.  
  442.  
  443.  
  444.  
  445. //-----------------------------------------------------------------------------
  446. // Name: 
  447. // Desc: When the 's' key or space bar is hit, the birds collapse together. Set
  448. //       the collapsed flag indicating the new state. Trigger two motifs to
  449. //       play. The first simply plays the collapse motif. The second plays a 
  450. //       cycling motif until the user lifts up, calling the Expand() function. 
  451. //-----------------------------------------------------------------------------
  452. void BoidMusic::Collapse()
  453. {
  454.     m_fCollapsed = TRUE;
  455.     if (m_dwBeatsSinceLastMotif)
  456.     {
  457.         if (m_pMotifSegments[5])
  458.         {
  459.             m_pPerformance->PlaySegment(
  460.                 m_pMotifSegments[5], (DMUS_SEGF_SECONDARY | DMUS_SEGF_GRID), 0, NULL);
  461.         }
  462.         if (m_pMotifSegments[3])
  463.         {
  464.             m_pMotifSegments[3]->SetRepeats(20);
  465.             m_pPerformance->PlaySegment(
  466.                 m_pMotifSegments[3], (DMUS_SEGF_SECONDARY | DMUS_SEGF_MEASURE), 0, NULL);
  467.         }
  468.         m_dwBeatsSinceLastMotif = 0;
  469.     }
  470. }
  471.  
  472.  
  473.  
  474.  
  475. //-----------------------------------------------------------------------------
  476. // Name: 
  477. // Desc: When the user releases the 's' key or space bar, the birds can move
  478. //       apart again. Notice that the repeating motif is turned off by calling
  479. //       stop on it.
  480. //-----------------------------------------------------------------------------
  481. void BoidMusic::Expand()
  482. {
  483.     m_fCollapsed = FALSE;
  484.     if (m_dwBeatsSinceLastMotif)
  485.     {
  486.         if (m_pMotifSegments[4])
  487.         {
  488.             m_pPerformance->PlaySegment(
  489.                 m_pMotifSegments[4], (DMUS_SEGF_SECONDARY | DMUS_SEGF_GRID), 0, NULL);
  490.         }
  491.         m_dwBeatsSinceLastMotif = 0;
  492.     }
  493.     if (m_pMotifSegments[3])
  494.     {
  495.         m_pPerformance->Stop(m_pMotifSegments[3], NULL, 0, 0);
  496.     }
  497. }
  498.  
  499.  
  500.  
  501.  
  502. //-----------------------------------------------------------------------------
  503. // Name: 
  504. // Desc: Close down all the music stuff.
  505. //-----------------------------------------------------------------------------
  506. void BoidMusic::EndMusic()
  507. {
  508.     m_Tool.m_pPerformance = NULL;
  509.     if (m_pPerformance)
  510.     {
  511.         m_pPerformance->Stop( NULL, NULL, 0, 0);
  512.     }
  513.     if (m_pSegment)
  514.     {
  515.         m_pSegment->Release();
  516.         m_pSegment = NULL;
  517.     }
  518.     if (m_pBand)
  519.     {
  520.         if(m_pPerformance)
  521.         {
  522.             m_pBand->Unload(m_pPerformance);
  523.         }
  524.         m_pBand->Release();
  525.         m_pBand = NULL;
  526.     }
  527.     if (m_pPort)
  528.     {
  529.         m_pPort->Release();
  530.         m_pPort = NULL;
  531.     }
  532.     if (m_pDMusic)
  533.     {
  534.         m_pDMusic->Release();
  535.         m_pDMusic = NULL;
  536.     }
  537.     if (m_pGraph)
  538.     {
  539.         m_pGraph->Release();
  540.         m_pGraph = NULL;
  541.     }
  542.     long x;
  543.     for (x = 0; x< 6; x++)
  544.     {
  545.         if (m_pTemplateSegments[x])
  546.         {
  547.             m_pTemplateSegments[x]->Release();
  548.             m_pTemplateSegments[x] = NULL;
  549.         }
  550.         if (m_pPrimarySegments[x])
  551.         {
  552.             m_pPrimarySegments[x]->Release();
  553.             m_pPrimarySegments[x] = NULL;
  554.         }
  555.         if (m_pMotifSegments[x])
  556.         {
  557.             m_pMotifSegments[x]->Release();
  558.             m_pMotifSegments[x] = NULL;
  559.         }
  560.     }
  561.     if (m_pStyle)
  562.     {
  563.         m_pStyle->Release();
  564.         m_pStyle = NULL;
  565.     }
  566.     if (m_pChordMap)
  567.     {
  568.         m_pChordMap->Release();
  569.         m_pChordMap = NULL;
  570.     }
  571.     if (m_pTransitionSegment)
  572.     {
  573.         m_pTransitionSegment->Release();
  574.         m_pTransitionSegment = NULL;
  575.     }
  576.     if (m_pComposer)
  577.     {
  578.         m_pComposer->Release();
  579.         m_pComposer = NULL;
  580.     }
  581.     if (m_pLoader)
  582.     {
  583.         m_pLoader->Release();
  584.         m_pLoader = NULL;
  585.     }
  586.     if (m_pPerformance)
  587.     {
  588.         m_pPerformance->Stop( NULL, NULL, 0, 0);
  589.         m_pPerformance->CloseDown();
  590.         m_pPerformance->Release();
  591.         m_pPerformance = NULL;
  592.     }
  593.     CoUninitialize();
  594. }
  595.  
  596. static char szDirectMusicMedia[] = "Media";
  597.  
  598.  
  599.  
  600.  
  601. //-----------------------------------------------------------------------------
  602. // Name: 
  603. // Desc:
  604. //-----------------------------------------------------------------------------
  605. BOOL BoidMusic::GetSearchPath(WCHAR wszPath[MAX_PATH])
  606. {
  607.     const TCHAR* szDir = DXUtil_GetDXSDKMediaPath();
  608.     mbstowcs(wszPath, szDir, MAX_PATH);
  609.  
  610.     return TRUE;
  611. }
  612.  
  613.  
  614.  
  615.  
  616. // Tool implementation follows. Pretty much all the meat is in the
  617. // ProcessEvent() method.
  618.  
  619. //-----------------------------------------------------------------------------
  620. // Name: 
  621. // Desc:
  622. //-----------------------------------------------------------------------------
  623. CTool::CTool()
  624. {
  625.     m_dwRatio = 100;
  626.     m_dwStartRatio = 100;
  627.     m_dwEcho = 1;
  628.     m_cRef = 0;
  629.     m_dwDelay = 96;
  630.     m_pPerformance = NULL;
  631. }
  632.  
  633.  
  634.  
  635.  
  636. //-----------------------------------------------------------------------------
  637. // Name: 
  638. // Desc:
  639. //-----------------------------------------------------------------------------
  640. CTool::~CTool()
  641. {
  642. }
  643.  
  644.  
  645. //-----------------------------------------------------------------------------
  646. // Name: 
  647. // Desc:
  648. //-----------------------------------------------------------------------------
  649. STDMETHODIMP CTool::QueryInterface( const IID &iid, void **ppv)       
  650. {
  651.     if (iid == IID_IDirectMusicTool)
  652.     {
  653.         *ppv = static_cast<IDirectMusicTool*>(this);
  654.     } else
  655.     {
  656.         *ppv = NULL;
  657.         return E_NOINTERFACE;
  658.     }
  659.  
  660.     reinterpret_cast<IUnknown*>(this)->AddRef();
  661.     return S_OK;
  662. }
  663.  
  664.  
  665.  
  666.  
  667. //-----------------------------------------------------------------------------
  668. // Name: 
  669. // Desc:
  670. //-----------------------------------------------------------------------------
  671. STDMETHODIMP_(ULONG) CTool::AddRef()
  672. {
  673.     return InterlockedIncrement(&m_cRef);
  674. }
  675.  
  676.  
  677.  
  678.  
  679. //-----------------------------------------------------------------------------
  680. // Name: 
  681. // Desc:
  682. //-----------------------------------------------------------------------------
  683. STDMETHODIMP_(ULONG) CTool::Release()
  684. {
  685.     if (!InterlockedDecrement(&m_cRef))
  686.     {
  687.         return 0;
  688.     }
  689.  
  690.     return m_cRef;
  691. }
  692.  
  693.  
  694.  
  695.  
  696. //-----------------------------------------------------------------------------
  697. // Name: 
  698. // Desc:
  699. //-----------------------------------------------------------------------------
  700. HRESULT STDMETHODCALLTYPE CTool::ProcessPMsg( IDirectMusicPerformance* pPerf, 
  701.                                               DMUS_PMSG* pMsg ) 
  702. {
  703.     HRESULT hr = S_OK;
  704.     if (pMsg->pGraph)
  705.     {
  706.         if (SUCCEEDED(pMsg->pGraph->StampPMsg(pMsg)))
  707.         {
  708.             hr = DMUS_S_REQUEUE;
  709.         }
  710.     }
  711.     switch( pMsg->dwType )
  712.     {
  713.     case DMUS_PMSGT_NOTE:
  714.         {
  715.             /*    If we receive a note, first adjust the duration
  716.                 by m_dwRatio.
  717.             */
  718.             DMUS_NOTE_PMSG *pNote = (DMUS_NOTE_PMSG *) pMsg;
  719.             if (m_dwRatio < 1) m_dwRatio = 1;
  720.             if (m_dwRatio > 400) m_dwRatio = 400;
  721.             pNote->mtDuration = MulDiv(pNote->mtDuration,m_dwRatio,100);
  722.             /*    Then, if it is on the PChannel of the melody,
  723.                 set it to echo the number of times established
  724.                 by m_dwEcho. Note that the echo algorithm is 
  725.                 quite simple but powerful: copy the event and play
  726.                 it on an adjacent PChannel. By playing it on a different
  727.                 PChannel, we take care of overlapping notes and
  728.                 we can have it panned differently.
  729.             */
  730.             if (m_dwEcho && (pNote->dwPChannel == 7))
  731.             {
  732.                 if (pPerf)
  733.                 {
  734.                     DWORD dwX;
  735.                     if (m_dwEcho > 3) m_dwEcho = 3;
  736.                     for (dwX = 0; dwX < m_dwEcho; dwX++)
  737.                     {
  738.                         DMUS_NOTE_PMSG * pEcho;
  739.                         if (SUCCEEDED(pPerf->AllocPMsg( sizeof(DMUS_NOTE_PMSG),
  740.                             (DMUS_PMSG**) &pEcho)))
  741.                         {
  742.                             static DWORD dwChannels[3] = { 6, 15, 0 };
  743.                             memcpy( pEcho, pNote, sizeof(DMUS_NOTE_PMSG) );
  744.                             pEcho->dwPChannel = dwChannels[dwX];
  745.                             pEcho->mtTime = pNote->mtTime + (m_dwDelay * (dwX + 1));
  746.                             pEcho->dwFlags = DMUS_PMSGF_MUSICTIME;
  747.                             if (pEcho->pGraph) pEcho->pGraph->AddRef();
  748.                             if (pEcho->pTool) pEcho->pTool->AddRef();
  749.                             pPerf->SendPMsg( (DMUS_PMSG*)pEcho) ;
  750.                         }
  751.                     }
  752.                 }
  753.             }
  754.         }
  755.         break;
  756.     case DMUS_PMSGT_CURVE:
  757.         break;
  758.     case DMUS_PMSGT_SYSEX:
  759.         break;
  760.     case DMUS_PMSGT_MIDI:
  761.         /*    Also, if we receive program changes, volumes, or pans on the 
  762.             PChannel of the melody, set up the echos to use the same patch,
  763.             a diminishing volume, and assign the pans appropriately.
  764.             This way, if a different band with different setting is loaded,
  765.             the echoed parts will all get reset appropriately.
  766.         */
  767.         {
  768.             DMUS_MIDI_PMSG *pMidi = (DMUS_MIDI_PMSG *) pMsg;
  769.             if (pMidi->dwPChannel == 7)
  770.             {
  771.                 DWORD dwX;
  772.                 for (dwX = 0;dwX < 3; dwX++)
  773.                 {
  774.                     DMUS_MIDI_PMSG * pEcho;
  775.                     if (SUCCEEDED(m_pPerformance->AllocPMsg( sizeof(DMUS_MIDI_PMSG),
  776.                         (DMUS_PMSG**) &pEcho)))
  777.                     {
  778.                         static DWORD dwChannels[3] = { 6, 15, 0 };
  779.                         static BYTE bPans[3] = { 80,0,120 };
  780.                         memcpy( pEcho, pMidi, sizeof(DMUS_MIDI_PMSG) );
  781.                         pEcho->dwPChannel = dwChannels[dwX];
  782.                         pEcho->mtTime = pMsg->mtTime + 20;
  783.                         pEcho->dwFlags = DMUS_PMSGF_MUSICTIME;
  784.                         if (pMidi->bStatus == 0xB0)
  785.                         {
  786.                             if (pMidi->bByte1 == 10)
  787.                             {
  788.                                 pEcho->bByte2 = bPans[dwX];
  789.                             }
  790.                             else if (pMidi->bByte1 == 7)
  791.                             {
  792.                                 pEcho->bByte2 = pMidi->bByte2 - (((BYTE)dwX+1) * 20);
  793.                                 if (pEcho->bByte2 > 127) pEcho->bByte2 = 10;
  794.                             }
  795.                         }
  796.                         if (pEcho->pGraph) pEcho->pGraph->AddRef();
  797.                         if (pEcho->pTool) pEcho->pTool->AddRef();
  798.                         m_pPerformance->SendPMsg( (DMUS_PMSG*)pEcho) ;
  799.                     }
  800.                 }
  801.             }
  802.         }
  803.         break;
  804.     case DMUS_PMSGT_PATCH:
  805.         break;
  806.     default:
  807.         break;
  808.     }
  809.  
  810.     return hr;
  811. }
  812.  
  813.  
  814.  
  815.  
  816. //-----------------------------------------------------------------------------
  817. // Name: 
  818. // Desc:
  819. //-----------------------------------------------------------------------------
  820. HRESULT STDMETHODCALLTYPE CTool::Flush( IDirectMusicPerformance* pPerf, 
  821.                                         DMUS_PMSG* pMsg, REFERENCE_TIME rt )
  822. {
  823.     return S_OK;
  824. }
  825.  
  826.  
  827.  
  828.  
  829. //-----------------------------------------------------------------------------
  830. // Name: 
  831. // Desc:
  832. //-----------------------------------------------------------------------------
  833. HRESULT STDMETHODCALLTYPE CTool::Init( IDirectMusicGraph* pGraph )
  834. {
  835.     return E_NOTIMPL;
  836. }
  837.  
  838.  
  839.  
  840.  
  841. //-----------------------------------------------------------------------------
  842. // Name: 
  843. // Desc:
  844. //-----------------------------------------------------------------------------
  845. HRESULT STDMETHODCALLTYPE  CTool::GetMsgDeliveryType( DWORD* pdwDeliveryType ) 
  846. {
  847.     return E_NOTIMPL;
  848. }
  849.  
  850.  
  851.  
  852.  
  853. //-----------------------------------------------------------------------------
  854. // Name: 
  855. // Desc:
  856. //-----------------------------------------------------------------------------
  857. HRESULT STDMETHODCALLTYPE  CTool::GetMediaTypeArraySize( DWORD* pdwNumElements ) 
  858. {
  859.     return E_NOTIMPL;
  860. }
  861.  
  862.  
  863.  
  864.  
  865. //-----------------------------------------------------------------------------
  866. // Name: 
  867. // Desc:
  868. //-----------------------------------------------------------------------------
  869. HRESULT STDMETHODCALLTYPE  CTool::GetMediaTypes( DWORD** padwMediaTypes, 
  870.                                                  DWORD dwNumElements ) 
  871. {
  872.     return E_NOTIMPL;
  873. }
  874.  
  875.  
  876.  
  877.  
  878. //-----------------------------------------------------------------------------
  879. // Name: 
  880. // Desc:
  881. //-----------------------------------------------------------------------------
  882. HRESULT BoidMusic::LoadMusic( HWND hwnd )
  883. {
  884.     HRESULT hr;
  885.        
  886.     CoInitialize(NULL);
  887.     hr = CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, 
  888.                            IID_IDirectMusicLoader, (VOID**)&m_pLoader );
  889.     if( FAILED(hr) ) 
  890.     {
  891.         OutputDebugString("Couldn't create CLSID_DirectMusicLoader\n");
  892.         return hr;
  893.     }
  894.  
  895.     WCHAR dir[MAX_PATH];
  896.     
  897.     m_pLoader->EnableCache(GUID_DirectMusicAllTypes, TRUE);
  898.  
  899.     hr = E_FAIL;
  900.     if (BoidMusic::GetSearchPath(dir))
  901.     {
  902.         hr = m_pLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, dir, FALSE);
  903.     }
  904.     if (FAILED(hr))
  905.     {
  906.         hr = m_pLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, L".", FALSE);
  907.     }
  908.     if (FAILED(hr))
  909.     {
  910.         OutputDebugString("Couldn't set DirectMusic search path");
  911.         return hr;
  912.     }
  913.  
  914.     hr = ::CoCreateInstance( CLSID_DirectMusicComposer, NULL, CLSCTX_INPROC, 
  915.                              IID_IDirectMusicComposer, (VOID**)&m_pComposer);
  916.     if( FAILED(hr) ) 
  917.     {
  918.         OutputDebugString("Couldn't create CLSID_DirectMusicComposer\n");
  919.         return hr;
  920.     }
  921.  
  922.     BOOL bResourcesOk = TRUE;
  923.  
  924.     bResourcesOk = bResourcesOk && SUCCEEDED( LoadDLS() );
  925.     bResourcesOk = bResourcesOk && LoadStyle();
  926.     bResourcesOk = bResourcesOk && LoadChordMap();
  927.     bResourcesOk = bResourcesOk && LoadTemplate(0,L"BoidsAA.tpl");
  928.     bResourcesOk = bResourcesOk && LoadTemplate(1,L"BoidB1.tpl");
  929.     bResourcesOk = bResourcesOk && LoadTemplate(2,L"BoidsC1.tpl");
  930.     bResourcesOk = bResourcesOk && LoadTemplate(3,L"BoidsCA.tpl");
  931.     bResourcesOk = bResourcesOk && LoadTemplate(4,L"BoidsCB.tpl");
  932.  
  933.     bResourcesOk = bResourcesOk && LoadTemplate(5,L"BoidsCC.tpl");
  934.     
  935.     ComposeSegment(0);
  936.     ComposeSegment(1);
  937.     ComposeSegment(2);
  938.     ComposeSegment(3);
  939.     ComposeSegment(4);
  940.     ComposeSegment(5);
  941.  
  942.     bResourcesOk = bResourcesOk && LoadSegment();
  943.     bResourcesOk = bResourcesOk && GetMotif(0, L"planet");
  944.     bResourcesOk = bResourcesOk && GetMotif(1, L"D motif");
  945.     bResourcesOk = bResourcesOk && GetMotif(2, L"motif RL med");
  946.     bResourcesOk = bResourcesOk && GetMotif(3, L"Cycle");
  947.     bResourcesOk = bResourcesOk && GetMotif(4, L"Expand");
  948.     bResourcesOk = bResourcesOk && GetMotif(5, L"Collapse");
  949.  
  950.     if (!bResourcesOk)
  951.     {
  952.         OutputDebugString("Couldn't load DirectMusic resources\n");
  953.         return E_FAIL;
  954.     }
  955.  
  956.     hr = CoCreateInstance( CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER,
  957.                            IID_IDirectMusic, (VOID**)&m_pDMusic);
  958.     if (FAILED(hr))
  959.     {
  960.         OutputDebugString("Couldn't create CLSID_DirectMusic\n");
  961.         return hr;
  962.     }
  963.  
  964.     hr = m_pDMusic->SetDirectSound(NULL, hwnd);
  965.     if (FAILED(hr))
  966.     {
  967.         OutputDebugString("Could't SetDirectSound on IDirectMusic\n");
  968.         return hr;
  969.     }
  970.  
  971.     DMUS_PORTPARAMS dmos;
  972.     DMUS_PORTCAPS dmpc;
  973.     GUID guidSynthGUID;
  974.     
  975.     hr = m_pDMusic->GetDefaultPort(&guidSynthGUID);
  976.     if (FAILED(hr))
  977.     {
  978.         OutputDebugString("Could't GetDefaultPort on IDirectMusic\n");
  979.         return hr;
  980.     }
  981.  
  982.     ZeroMemory(&dmos, sizeof(dmos));
  983.     dmos.dwSize = sizeof(DMUS_PORTPARAMS);
  984.     dmos.dwChannelGroups = 1;
  985.     dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
  986.  
  987.     hr = m_pDMusic->CreatePort( guidSynthGUID, &dmos, &m_pPort, NULL );
  988.     if (FAILED(hr))
  989.     {
  990.         OutputDebugString("Couldn't CreatePort on IDirectMusic\n");
  991.         return hr;
  992.     }
  993.  
  994.     ZeroMemory(&dmpc, sizeof(dmpc));
  995.     dmpc.dwSize = sizeof(DMUS_PORTCAPS);
  996.  
  997.     hr = m_pPort->GetCaps(&dmpc);
  998.     if (FAILED(hr))
  999.     {
  1000.         OutputDebugString("Couldn't GetCaps on IDirectMusicPort\n");
  1001.         return hr;
  1002.     }
  1003.  
  1004.     if ((dmpc.dwClass != DMUS_PC_OUTPUTCLASS) || !(dmpc.dwFlags & DMUS_PC_DLS))
  1005.     {
  1006.         m_pPort->Release();
  1007.         m_pPort = NULL;
  1008.     }
  1009.  
  1010.     if (!m_pPort)
  1011.     {
  1012.         hr = E_FAIL;
  1013.  
  1014.         for (DWORD index = 0; ; index++)
  1015.         {
  1016.             ZeroMemory(&dmpc, sizeof(dmpc));
  1017.             dmpc.dwSize = sizeof(DMUS_PORTCAPS);
  1018.  
  1019.             hr = m_pDMusic->EnumPort(index, &dmpc);
  1020.             if(SUCCEEDED(hr) && hr != S_FALSE)
  1021.             {
  1022.                 if ( (dmpc.dwClass == DMUS_PC_OUTPUTCLASS) && 
  1023.                      (dmpc.dwFlags & DMUS_PC_DLS) )
  1024.                 {
  1025.                     CopyMemory(&guidSynthGUID, &dmpc.guidPort, sizeof(GUID));
  1026.                     
  1027.                     ZeroMemory(&dmos, sizeof(dmos));
  1028.                     dmos.dwSize = sizeof(DMUS_PORTPARAMS);
  1029.                     dmos.dwChannelGroups = 1;
  1030.                     dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
  1031.  
  1032.                     hr = m_pDMusic->CreatePort( guidSynthGUID, &dmos,
  1033.                                                 &m_pPort, NULL );
  1034.                     break;
  1035.                 }
  1036.             }
  1037.             else
  1038.             {
  1039.                 break;
  1040.             }
  1041.         }
  1042.     }
  1043.  
  1044.     if (FAILED(hr))
  1045.     {
  1046.         OutputDebugString("Couldn't find or CreatePort software synthesizer\n");
  1047.         return hr;
  1048.     }
  1049.  
  1050.     hr = CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_ALL, 
  1051.                            IID_IDirectMusicPerformance, (VOID**)&m_pPerformance );
  1052.     if (FAILED(hr))
  1053.     {
  1054.         OutputDebugString("Couldn't create CLSID_DirectMusicPerformance\n");
  1055.         return hr;
  1056.     }
  1057.  
  1058.     hr = m_pPerformance->Init(&m_pDMusic, NULL, NULL);
  1059.     if (FAILED(hr))
  1060.     {
  1061.         OutputDebugString("Couldn't init CLSID_DirectMusicPerformance\n");
  1062.         return hr;
  1063.     }
  1064.  
  1065.     m_pPerformance->AddPort(m_pPort );
  1066.     m_pPerformance->AssignPChannelBlock(0, m_pPort, 1);
  1067.     m_hNotify = CreateEvent( NULL, FALSE, FALSE, NULL );
  1068.     if( m_hNotify )
  1069.     {
  1070.         GUID guid;
  1071.         m_pPerformance->SetNotificationHandle( m_hNotify, 0 );
  1072.         guid = GUID_NOTIFICATION_MEASUREANDBEAT;
  1073.         m_pPerformance->AddNotificationType( guid );
  1074.     }
  1075.     m_Tool.m_pPerformance = m_pPerformance;
  1076.     if (m_pBand)
  1077.     {
  1078.         m_pBand->Download(m_pPerformance);
  1079.     }
  1080.  
  1081.     hr = ::CoCreateInstance( CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC, 
  1082.                              IID_IDirectMusicGraph, (VOID**)&m_pGraph );
  1083.     if (FAILED(hr))
  1084.     {
  1085.         OutputDebugString("Couldn't create CLSID_DirectMusicGraph\n");
  1086.         return hr;
  1087.     }
  1088.  
  1089.     m_pPerformance->SetGraph(m_pGraph);
  1090.     IDirectMusicTool *pTool;
  1091.     hr = m_Tool.QueryInterface(IID_IDirectMusicTool, (void**)&pTool);
  1092.     if (FAILED(hr))
  1093.     {
  1094.         OutputDebugString("Couldn't InsertTool on graph\n");
  1095.         return hr;
  1096.     }
  1097.  
  1098.     m_pGraph->InsertTool( pTool, 0, NULL, 0);
  1099.  
  1100.     return S_OK;;
  1101. }
  1102.  
  1103.  
  1104. //-----------------------------------------------------------------------------
  1105. // Name: 
  1106. // Desc:
  1107. //-----------------------------------------------------------------------------
  1108. void BoidMusic::Activate( BOOL bActive )
  1109. {
  1110.     if (m_pDMusic)
  1111.     {
  1112.         m_pDMusic->Activate(bActive);
  1113.     }
  1114. }
  1115.